﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Client client = new Client();
            client.ConnectionServer();
            while (true)
            {
                string a = Console.ReadLine();
                if (a == "stop")
                {
                    break;
                }
                client.SendMessage(a);
            }
            client.Disconnect();
        }
    }

    class Client
    {
        [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        struct Pack
        {
            public int len;
            public byte[] buff;

            public byte[] ToBytes()
            {
                byte[] bytes = new byte[len];
                bytes[0] = (byte)(len & 0xFF);
                bytes[1] = (byte)((len & 0xFF00) >> 8);
                bytes[2] = (byte)((len & 0xFF0000) >> 16);
                bytes[3] = (byte)((len >> 24) & 0xFF);

                for (int i = 4; i < len; i++)
                {
                    bytes[i] = buff[i - 4];
                }
                return bytes;
            }

            // 序列化
            public byte[] Serialize()
            {
                MemoryStream output = new MemoryStream();
                BinaryWriter writer = new BinaryWriter(output);
                writer.Write(this.len);
                writer.Write(this.buff);
                writer.Close();
                output.Close();
                return output.ToArray();
            }

            // 反序列化
            public object Deserialize(byte[] infos)
            {
                if ((infos == null) || (infos.Length < 4))
                {
                    return null;
                }
                Pack pack = new Pack();
                MemoryStream input = new MemoryStream(infos);
                BinaryReader reader = new BinaryReader(input);
                pack.len = reader.ReadInt32();
                pack.buff = reader.ReadBytes(pack.len - sizeof(int));
                reader.Close();
                input.Close();
                return pack;
            }
        }
        byte[] dataBuffer = new byte[1024];
        int serverPort = 12345;
        string serverIP = "192.168.1.103";
        Socket client;

        public int Port
        {
            get
            {
                return serverPort;
            }
            set
            {
                serverPort = value;
            }
        }

        public string IP
        {
            get
            {
                return serverIP;
            }
            set
            {
                serverIP = value;
            }
        }

        public void ConnectionServer()
        {
            // 连接服务器
            try
            {
                client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPAddress ip = IPAddress.Parse(serverIP);
                IPEndPoint iep = new IPEndPoint(ip, serverPort);
                client.BeginConnect(iep, new AsyncCallback(ConnectCallBack), null);
            }
            catch { }
        }

        private void ConnectCallBack(IAsyncResult asy)
        {
            try
            {
                client.EndConnect(asy);
                client.BeginReceive(dataBuffer, 0, dataBuffer.Length, SocketFlags.None, new AsyncCallback(RecieveCallBack), null);
            }
            catch { }
        }

        private void RecieveCallBack(IAsyncResult asy)
        {
            try
            {
                int iRx = client.EndReceive(asy);
                byte[] byte_Receive = new byte[iRx];
                for (int i = 0; i < iRx; i++)
                {
                    byte_Receive[i] = dataBuffer[i];
                }
                Console.WriteLine(byte_Receive);

                // 继续监听下一次的数据接收
                client.BeginReceive(dataBuffer, 0, dataBuffer.Length, SocketFlags.None, new AsyncCallback(RecieveCallBack), null);
            }
            catch { }
        }

        public void SendMessage(string buffer)
        {
            try
            {
                Pack pack;
                pack.buff = Encoding.Default.GetBytes(buffer);
                pack.len = pack.buff.Length + sizeof(int);
                client.BeginSend(pack.Serialize(), 0, pack.len, SocketFlags.None, new AsyncCallback(SendCallBack), null);
            }
            catch { }
        }

        private void SendCallBack(IAsyncResult asy)
        {
            try
            {
                int bytesSent = client.EndSend(asy);
                Console.WriteLine("Send {0} bytes", bytesSent);
            }
            catch { }
        }

        public void Disconnect()
        {
            try
            {
                client.Shutdown(SocketShutdown.Both);
                client.Close();
            }
            catch { }
        }

        //将Byte转换为结构体类型，结构体中不能包含数组
        public static byte[] StructToBytes<T>(T obj)
        {
            int size = Marshal.SizeOf(obj);
            byte[] bytes = new byte[size];
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            //将结构体拷到分配好的内存空间
            Marshal.StructureToPtr(obj, structPtr, false);
            //从内存空间拷贝到byte 数组
            Marshal.Copy(structPtr, bytes, 0, size);
            //释放内存空间
            Marshal.FreeHGlobal(structPtr);
            return bytes;
        }

        /// Byte数组转结构体，结构体中不能包含数组
        public static object BytesToStuct(byte[] bytes, Type type)
        {
            //得到结构体的大小
            int size = Marshal.SizeOf(type);
            //byte数组长度小于结构体的大小
            if (size > bytes.Length)
            {
                //返回空
                return null;
            }
            //分配结构体大小的内存空间
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            //将byte数组拷到分配好的内存空间
            Marshal.Copy(bytes, 0, structPtr, size);
            //将内存空间转换为目标结构体
            object obj = Marshal.PtrToStructure(structPtr, type);
            //释放内存空间
            Marshal.FreeHGlobal(structPtr);
            //返回结构体
            return obj;
        }
    }
}
